package de.bloxel.core.water;

import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;

import de.bloxel.core.BloxelFactory.BloxelType;
import de.bloxel.core.events.Event;
import de.bloxel.core.events.EventListener;
import de.bloxel.ui.BloxelActionController;
import de.bloxel.ui.BloxelApplication;

public class WaterFiller implements EventListener {

  private static class Water {
    public Vector3f position;
    public float quantity;

    public Water(final WaterEvent theEvent) {
      position = theEvent.getWaterSourcePositionCenter();
      quantity = theEvent.getWaterQuantity();
    }
  }

  private final BloxelApplication bloxelApplication;
  private final BloxelActionController bloxelActionController;
  private boolean xPosFree = true;
  private boolean xNegFree = true;
  private boolean untenFrei = true;
  private boolean zPosFree;
  private boolean zNegFree;

  public WaterFiller(final BloxelApplication theBloxelApplication,
      final BloxelActionController theBloxelActionController) {
    bloxelApplication = theBloxelApplication;
    bloxelActionController = theBloxelActionController;
  }

  private void beginFloodingGround(final Water water) {
    if (xPosFree && water.quantity > 0) {
      final Vector3f newWaterTarget = water.position.add(1f, 0, 0);
      // TODO send event for bloxel creation
      bloxelActionController.getTerrainChunk().addTerrainElement(newWaterTarget, BloxelType.WATER);
      bloxelApplication.updateTerrain();
      bloxelApplication.eventManager
          .queueEvent(new WaterEvent("waterSourceCreate", newWaterTarget, water.quantity -= 1));
    }
    if (xNegFree && water.quantity > 0) {
      final Vector3f newWaterTarget = water.position.add(-1f, 0f, 0);
      // TODO send event for bloxel creation
      bloxelActionController.getTerrainChunk().addTerrainElement(newWaterTarget, BloxelType.WATER);
      bloxelApplication.updateTerrain();
      bloxelApplication.eventManager
          .queueEvent(new WaterEvent("waterSourceCreate", newWaterTarget, water.quantity -= 1));
    }
    if (zPosFree && water.quantity > 0) {
      final Vector3f newWaterTarget = water.position.add(0, 0, 1f);
      // TODO send event for bloxel creation
      bloxelActionController.getTerrainChunk().addTerrainElement(newWaterTarget, BloxelType.WATER);
      bloxelApplication.updateTerrain();
      bloxelApplication.eventManager
          .queueEvent(new WaterEvent("waterSourceCreate", newWaterTarget, water.quantity -= 1));
    }
    if (zNegFree && water.quantity > 0) {
      final Vector3f newWaterTarget = water.position.add(0, 0f, -1f);
      // TODO send event for bloxel creation
      bloxelActionController.getTerrainChunk().addTerrainElement(newWaterTarget, BloxelType.WATER);
      bloxelApplication.updateTerrain();
      bloxelApplication.eventManager
          .queueEvent(new WaterEvent("waterSourceCreate", newWaterTarget, water.quantity -= 1));
    }
    xPosFree = true;
    xNegFree = true;
    zPosFree = true;
    zNegFree = true;
    untenFrei = true;
  }

  private void fillWater(final Water water) {
    if (water.quantity < 0) {
      return;
    }
    final Node bloxelsNode = bloxelApplication.getRootNode();
    for (final Spatial bloxel : ((Node) bloxelsNode.getChild("Bloxels")).getChildren()) {
      if (water.position.add(1f, 0, 0).equals(bloxel.getWorldBound().getCenter())) {
        xPosFree = false;
      }
      if (water.position.add(-1, 0, 0).equals(bloxel.getWorldBound().getCenter())) {
        xNegFree = false;
      }
      if (water.position.add(0, 0, 1f).equals(bloxel.getWorldBound().getCenter())) {
        zPosFree = false;
      }
      if (water.position.add(0, 0, -1f).equals(bloxel.getWorldBound().getCenter())) {
        zNegFree = false;
      }
      if (water.position.add(0, -1f, 0).equals(bloxel.getWorldBound().getCenter())) {
        untenFrei = false;
      }
    }
    if (untenFrei && water.quantity > 0) {
      final Vector3f newWaterTarget = water.position.add(0, -1f, 0f);
      // TODO send event for bloxel creation
      bloxelActionController.getTerrainChunk().addTerrainElement(newWaterTarget, BloxelType.WATER);
      bloxelApplication.updateTerrain();
      bloxelApplication.eventManager
          .queueEvent(new WaterEvent("waterSourceCreate", newWaterTarget, water.quantity -= 1));
    } else {
      beginFloodingGround(water);
    }
  }

  @Override
  public boolean handleEvent(final Event theEvent) {
    if (theEvent.getType().equals("waterSourceCreate")) {
      fillWater(new Water((WaterEvent) theEvent));
    }
    return false;
  }
}
